# config.py
import platform
import shutil
import os
import re
import sys
from typing import List, Dict, Any
import psutil  # 确保导入psutil

class CleanerConfig:
    """清理器配置类，管理系统类型、目标目录和平台特定配置"""
    
    # 通用软件包扩展名配置
    COMMON_PACKAGE_EXTS = {
        'windows': ['exe', 'msi', 'zip', 'rar', '7z', 'iso', 'cab', 'appx'],
        'linux': ['deb', 'rpm', 'tar.gz', 'tar.xz', 'zip', 'rar', 'sh'],
        'macos': ['dmg', 'pkg', 'zip', 'rar', 'xip']
    }

    # 内存保护相关配置
    memory_threshold = 75  # 内存使用阈值百分比
    memory_check_interval = 5  # 内存检查间隔（秒）
    
    def __init__(self, system_type: str = None, clean_dirs: List[str] = None, 
                 link_type: str = 'delete', full_scan: bool = False, fast_mode: bool = False,
                 hash_algorithm: str = 'md5'):
        self.hash_algorithm = hash_algorithm
        self.system_type = system_type or self._detect_system()
        self.full_scan = full_scan
        self.target_dirs = clean_dirs or (self._get_full_disk_dirs() if full_scan else self._get_default_dirs())
        self.link_type = link_type
        self.check_folders = False
        self.folder_depth = 3
        self.platform_config = self._get_platform_config()
        self.custom_exts = []  # 用户自定义的软件包扩展名
        self.include_keywords = []       # 包含的关键字列表（支持正则表达式）
        self.keyword_logic = "or"        # 逻辑关系：'or'（或）/'and'（与）
        self.recursive = True            # 是否递归扫描子目录
        self.exclude_extensions = []     # 要排除的文件后缀列表
        self.exclude_dirs = []           # 排除目录列表
        self._init_exclude_dirs()        # 初始化排除目录
        self.fast_mode = fast_mode       # 快速扫描模式

    @staticmethod
    def get_hash_algorithms() -> Dict[str, Dict[str, str]]:
        """获取支持的哈希算法及其属性"""
        return {
            'md5': {'name': 'MD5', 'speed': '快', 'security': '较低'},
            'sha1': {'name': 'SHA-1', 'speed': '中等', 'security': '中'},
            'sha256': {'name': 'SHA-256', 'speed': '较慢', 'security': '高'},
            'blake2': {'name': 'BLAKE2', 'speed': '最快', 'security': '高'}
        }
    

    def get_cache_dir(self) -> str:
        """获取剩余空间最大的磁盘分区作为缓存目录"""
        max_free = 0
        cache_dir = None
        
        if self.system_type == 'windows':
            for drive in self._get_full_disk_dirs():
                try:
                    usage = shutil.disk_usage(drive)
                    if usage.free > max_free:
                        max_free = usage.free
                        cache_dir = drive
                except:
                    pass
        else:
            # Linux/Mac 系统
            partitions = ["/"] + [f for f in os.listdir("/mnt") if os.path.isdir(os.path.join("/mnt", f))] + [os.path.expanduser("~")]
            for part in partitions:
                try:
                    usage = shutil.disk_usage(part)
                    if usage.free > max_free:
                        max_free = usage.free
                        cache_dir = part
                except:
                    pass
        return cache_dir or os.path.expanduser("~")
    
    def _init_exclude_dirs(self):
        """初始化排除目录列表"""
        # 系统级排除目录
        system_excludes = []
        if self.system_type == 'windows':
            system_excludes = [
                'C:\\Windows',
                'C:\\Program Files',
                'C:\\Program Files (x86)',
                'C:\\ProgramData',
                os.path.join(os.environ.get('APPDATA', ''), '..', 'Local', 'Temp'),
                os.path.join(os.environ.get('USERPROFILE', ''), 'AppData'),
                os.path.join(os.environ.get('USERPROFILE', ''), 'Application Data'),
            ]
        elif self.system_type == 'linux':
            system_excludes = [
                '/proc',
                '/sys',
                '/dev',
                '/run',
                '/boot',
                '/var/cache',
                '/var/tmp',
                '/snap',
                '/usr/lib',
                '/usr/share',
            ]
        elif self.system_type == 'macos':
            system_excludes = [
                '/System',
                '/Library',
                '/private',
                '/usr/lib',
                '/usr/share',
                '/usr/standalone',
            ]
        
        # 浏览器缓存目录
        browser_excludes = [
            os.path.join(os.environ.get('USERPROFILE', ''), 'AppData', 'Local', '360se6'),
            os.path.join(os.environ.get('USERPROFILE', ''), 'AppData', 'Roaming', '360huabao'),
            os.path.join(os.environ.get('HOME', ''), '.cache'),
            os.path.join(os.environ.get('HOME', ''), '.config', 'google-chrome'),
            os.path.join(os.environ.get('HOME', ''), '.mozilla'),
        ]
        
        # 过滤掉不存在的目录
        self.exclude_dirs = [d for d in (system_excludes + browser_excludes) if d and os.path.exists(d)]

    def set_keyword_filters(self, keywords: List[str], logic: str = "or", recursive: bool = True):
        """设置目录过滤关键字"""
        self.include_keywords = [kw.strip() for kw in keywords if kw.strip()]
        self.keyword_logic = logic.lower()
        self.recursive = recursive

    def set_exclude_extensions(self, exts: List[str]):
        """设置要排除的文件后缀"""
        self.exclude_extensions = [ext.strip().lower() for ext in exts if ext.strip()]
    
    def is_extension_excluded(self, file_path: str) -> bool:
        """检查文件后缀是否在排除列表中"""
        if not self.exclude_extensions:
            return False
        
        # 获取文件后缀（不带点）
        _, ext = os.path.splitext(file_path)
        if ext:  # 确保有后缀
            ext = ext[1:].lower()  # 去掉点并转为小写
            return ext in self.exclude_extensions
        return False

    def is_dir_allowed(self, dir_path: str) -> bool:
        """判断目录是否符合过滤条件"""
        if not self.include_keywords:
            return True  # 无过滤时允许所有目录
        
        # 先检查排除目录
        if self.is_dir_excluded(dir_path):
            return False
            
        # 特殊处理：总是允许用户主目录
        home_dir = os.path.expanduser('~')
        if dir_path.startswith(home_dir) and not self.full_scan:
            return True
        
        dir_name = os.path.basename(dir_path)
        matches = [bool(re.search(kw, dir_name, re.IGNORECASE)) for kw in self.include_keywords]
        
        if self.keyword_logic == "or":
            return any(matches)
        elif self.keyword_logic == "and":
            return all(matches)
        return False
        
    def is_dir_excluded(self, dir_path: str) -> bool:
        """检查目录是否在排除列表中"""
        abs_path = os.path.abspath(dir_path)
        for exclude_dir in self.exclude_dirs:
            if abs_path.startswith(os.path.abspath(exclude_dir)):
                return True
        return False
        
    def _detect_system(self) -> str:
        """自动检测操作系统类型"""
        system = platform.system().lower()
        if system == 'windows':
            return 'windows'
        elif system == 'linux':
            return 'linux'
        elif system == 'darwin':
            return 'macos'
        return 'unknown'
    
    def _get_full_disk_dirs(self) -> List[str]:
        """获取用于全盘扫描的目录列表"""
        # 使用psutil获取所有磁盘分区
        try:
            partitions = psutil.disk_partitions(all=False)
            drives = []
            
            for partition in partitions:
                # 只处理本地磁盘（排除网络驱动器等）
                if partition.fstype and 'cdrom' not in partition.opts:
                    try:
                        # 检查分区是否可访问
                        usage = psutil.disk_usage(partition.mountpoint)
                        if usage.total > 0:  # 确保分区有空间
                            drives.append(partition.mountpoint)
                    except Exception:
                        # 忽略无法访问的分区
                        continue
            
            # 在Windows上确保路径格式正确
            if self.system_type == 'windows' and drives:
                # 确保路径以反斜杠结尾
                return [d.rstrip('\\') + '\\' for d in drives]
            else:
                return drives
        except:
            # 如果psutil不可用，则使用备选方案
            if self.system_type == 'windows':
                # 尝试获取所有可能的驱动器
                possible_drives = []
                for drive_letter in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
                    drive_path = f"{drive_letter}:\\"
                    if os.path.exists(drive_path):
                        possible_drives.append(drive_path)
                return possible_drives or ['C:\\']  # 默认扫描C盘
            elif self.system_type == 'linux':
                return ['/']  # 根目录
            elif self.system_type == 'macos':
                return ['/']  # 根目录
        return [os.path.expanduser('~')]  # 用户主目录作为备选
    
    def _get_default_dirs(self) -> List[str]:
        """获取默认扫描目录（非全盘扫描时使用）"""
        if self.system_type == 'windows':
            return [
                os.path.expanduser('~\\Downloads'),
                os.path.expanduser('~\\Documents'),
                os.path.expanduser('~\\Desktop')
            ]
        elif self.system_type == 'linux':
            return [os.path.expanduser('~/Downloads'), os.path.expanduser('~/Documents')]
        elif self.system_type == 'macos':
            return [os.path.expanduser('~/Downloads'), os.path.expanduser('~/Documents')]
        return [os.path.expanduser('~')]
 
    def _get_platform_config(self) -> Dict[str, Any]:
        """获取平台特定的配置"""
        config = {
            'windows': {
                'package_ext': self.COMMON_PACKAGE_EXTS['windows'],
                'temp_dirs': [
                    os.path.expanduser('~\\AppData\\Local\\Temp'),
                    os.path.join(os.environ.get('WINDIR', 'C:\\Windows'), 'Temp')
                ]
            },
            'linux': {
                'package_ext': self.COMMON_PACKAGE_EXTS['linux'],
                'temp_dirs': ['/tmp', os.path.expanduser('~/.cache')]
            },
            'macos': {
                'package_ext': self.COMMON_PACKAGE_EXTS['macos'],
                'temp_dirs': [
                    os.path.expanduser('~/Library/Caches'),
                    os.path.expanduser('~/Library/Application Support/Caches')
                ]
            }
        }
        return config.get(self.system_type, {})
    
    def add_custom_extensions(self, exts: List[str]):
        """添加用户自定义的软件包扩展名"""
        self.custom_exts.extend([ext.strip().lower() for ext in exts if ext.strip()])
        
    def get_all_package_extensions(self) -> List[str]:
        """获取所有软件包扩展名（内置+自定义）"""
        platform_exts = self.platform_config.get('package_ext', [])
        return list(set(platform_exts + self.custom_exts))
    
    def validate_directories(self) -> List[str]:
        """验证并返回存在的目录列表"""
        valid_dirs = []
        for d in self.target_dirs:
            if os.path.exists(d):
                valid_dirs.append(d)
            else:
                print(f"警告：目录不存在 - {d}")
        return valid_dirs

    def set_target_dirs(self, dirs: List[str]):
        """设置目标目录"""
        self.target_dirs = dirs
        

    def get_cache_dir(self) -> str:
        """获取剩余空间最大的磁盘分区作为缓存目录"""
        max_free = 0
        cache_dir = None
        
        if self.system_type == 'windows':
            for drive in self._get_full_disk_dirs():
                try:
                    usage = shutil.disk_usage(drive)
                    if usage.free > max_free:
                        max_free = usage.free
                        cache_dir = drive
                except:
                    pass
        else:
            # Linux/Mac 系统
            partitions = ["/"] + [f for f in os.listdir("/mnt") if os.path.isdir(os.path.join("/mnt", f))] + [os.path.expanduser("~")]
            for part in partitions:
                try:
                    usage = shutil.disk_usage(part)
                    if usage.free > max_free:
                        max_free = usage.free
                        cache_dir = part
                except:
                    pass
        return cache_dir or os.path.expanduser("~")